home *** CD-ROM | disk | FTP | other *** search
- #include <stdio.h>
-
- /*
- * Data declaration keywords
- */
- #define DEFINE 1
- #define INCLUDE 2
- #define TYPEDEF 3
- #define EXTERN 4
- #define STATIC 5
- #define AUTO 6
- #define REGISTER 7
- #define UNSIGNED 8
- #define CHAR 9
- #define INT 10
- #define LONG 11
- #define FLOAT 12
- #define DOUBLE 13
- #define STRUCT 14
- #define UNION 15
- #define VOID 16
- #define ENUM 17
-
- #define DECLARATIONS ENUM
- /*
- * Other keywords
- */
- #define IF 18
- #define ELSE 19
- #define FOR 20
- #define DO 21
- #define WHILE 22
- #define BREAK 23
- #define CONTINUE 24
- #define GOTO 25
- #define RETURN 26
- #define SWITCH 27
- #define CASE 28
- #define DEFAULT 29
- #define SIZEOF 30
-
- #define KEYWORDS SIZEOF
-
- #define SYMBOL 31
- #define NEWLINE 127
-
- /*
- * File stuff:
- */
- char *Filename; /* current input file name */
- #ifdef BDS_C
- char Fileptr[BUFSIZ]; /* and I/O buffer for BDS C */
- #else
- FILE *Fileptr; /* everybody else uses a file pointer */
- #endif
- int Inline; /* current input line number */
- #define PAGELEN 55 /* max page length */
- int Outline; /* current output line # for paginating */
- int Page;
-
- #define FILESTACKSZ 10 /* maximum #include nesting */
- #define FILENMSZ 20 /* maximum file name length */
- struct fstack { /* #include file stack */
- char fname[FILENMSZ]; /* name of current file (before #include) */
- #ifdef BDS_C
- char fptr[BUFSIZ]; /* and its file I/O buffer */
- #else
- FILE *fptr; /* or file ptr respectively */
- #endif
- int fline; /* line # in current file */
- char fbraces; /* current {} count */
- char fparens; /* current () count */
- } Filestack[ FILESTACKSZ ];
- int Nextfile; /* next available slot in Filestack */
-
- #define OUTBUFSZ 2000
- char Outbuf[ OUTBUFSZ ]; /* output buffer */
- char *Outend; /* points to end of Outbuf */
- char *Nextout; /* points to next position in Outbuf */
-
- /*
- * Command line flags
- */
- char Doincludes; /* process #include files */
- char Docomments; /* print comments */
- char Dodefines; /* print #define statements */
- char Debug; /* program debug enable flag */
-
- /*
- * Parser variables
- */
- #define TOKENBUFSZ 2000 /* largest string or comment block */
- char Tokenbuf[ TOKENBUFSZ+4 ]; /* current input "token" */
- char *Tokenstart; /* ptr to first non-space char in Tokenbuf */
- char Token; /* first non-space char in Tokenbuf */
- char Braces, Parens; /* {} and () parity counters */
-
- /*
- * Current function information
- */
- #define MAXLINELEN 80
- char Curfunc[ MAXLINELEN ]; /* name of current function */
- #define MAXREFS 500
- char *Refers[ MAXREFS ]; /* references to symbols made by Curfunc */
- int Nextref;
-
-
- main( argc, argv )
- int argc;
- char **argv;
- {
- /*
- * Initialize some pointers first.
- */
- Nextout = Outbuf;
- Outend = Outbuf + OUTBUFSZ;
-
- /*
- * Pares command line arguments.
- */
- while ( --argc )
- {
- if ( **++argv=='-' )
- {
- switch ( toupper( *++*argv ) )
- {
- case 'I':
- Doincludes = 1;
- break;
- case 'C':
- Docomments = 1;
- break;
- case 'D':
- Dodefines = 1;
- break;
- case 'Y':
- ++Debug;
- break;
- default:
- usage();
- }
- }
- else
- /*
- * Not a switch, so it must be a file name.
- */
- process( *argv );
- }
- }
-
- process( fn )
- char *fn;
- {
- int type, c, i;
- char name[ MAXLINELEN ];
-
- if ( !newfile( fn ) )
- return;
-
- newpage();
-
- error( "" );
- while ( getoken() )
- {
- if ( Token==INCLUDE )
- {
- /*
- * Found a #include preprocessor directive.
- * Search for file name immediately following
- * a " or <
- */
- while ( (c = needchr()) != -1 && c!='"' && c!='<' )
- ;
- i = 0;
- while ( (c = needchr()) != -1 && c!='"' && c!='>' )
- if ( i<FILENMSZ )
- name[ i++ ] = c;
- name[ i ] = 0;
- if ( Doincludes )
- {
- pushfile();
- process( name );
- popfile();
- error( "" );
- }
- }
- else if ( Token==DEFINE )
- {
- /*
- * Print all #define preprocessor directives.
- */
- if ( Dodefines )
- putstr( Tokenstart );
- do
- {
- getoken();
- if ( Dodefines )
- putstr( Tokenbuf );
- }
- while ( Token!=NEWLINE );
- if ( Debug && Dodefines )
- printf( "<- #define ***\n" );
- }
- else if ( Token=='#' )
- {
- /*
- * Skip all other preprocessor directives
- */
- while ( getoken() != NEWLINE );
- }
- else if ( Token==SYMBOL )
- {
- if ( Braces )
- {
- /*
- * It's a symbol reference inside a function.
- */
- strcpy( name, Tokenstart );
- reference( name );
- }
- else
- {
- /*
- * It's a function (possibly) or some kinda
- * typedef/define declaration, like:
- *
- * FILE *fptr;
- *
- * We don't really know until we see the
- * telltale ';' that tells us it's a decl.,
- * or the '(' if it's a function, like:
- *
- * FILE *fopen(f,m) char *f, *m; { ...
- */
- declaration( name );
- }
- }
- else if ( Token <= DECLARATIONS )
- declaration( name );
- }
- dumprefs();
- flush();
- endfile();
- }
-
- declaration( name )
- char name[];
- {
- /*
- * It's definately a declaration of some kind, although it could be
- * either a data declaration or a function definition or declaration,
- * i.e., anything that resembles the following examples:
- *
- * char *cp;
- * char *gets();
- * char *gets(buf,len,fp) ... {...
- */
- char brace, prevtoken;
-
- putstr( Tokenstart );
- brace = Braces;
- do
- {
- if ( Token==SYMBOL )
- {
- /*
- * Previous token is a SYMBOL - save
- * it just in case this is a function
- * definition.
- */
- strcpy( name, Tokenstart );
- prevtoken = SYMBOL;
- }
- else
- prevtoken = 0;
- /*
- * Now get next input token
- */
- getoken();
-
- if ( Token=='(' && prevtoken==SYMBOL )
- {
- /*
- * Function definitions and declarations are
- * recognized by the telltale '('immediately
- * following a SYMBOL token.
- * It's a function definition if the first
- * token following the "( ... )" is NOT a
- * comma or semicolon, otherwise it's a
- * declaration.
- */
- if ( Parens )
- putstr( Tokenbuf );
- while ( Parens )
- {
- getoken();
- putstr( Tokenbuf );
- }
- getoken();
- if ( Token!=',' && Token!=';' )
- {
- /*
- * It's a function definition!
- */
- if ( Debug )
- printf("*** function ***");
- putstr( "\n----------" );
- /*
- * Dump previous function's symbol references
- * and copy current function's name into
- * global "current function name buffer".
- */
- dumprefs();
- strcpy( Curfunc, name );
- goto done;
- }
- /*
- * Otherwise, it's a function declaration of
- * the form:
- *
- * char *gets(), putc();
- */
- }
- putstr( Tokenbuf );
- }
- while ( Token && (Token!=';' || Braces!=brace) );
- /*
- * If this is a global declaration, first dump current function's
- * symbol references (if any).
- */
- if ( !Braces && Nextref )
- dumprefs();
-
- if ( Debug )
- printf( "<-declaration ***" );
- done:
- putchr( '\n' );
- flush();
- }
-
- reference( name )
- char name[];
- {
- /*
- * It's a reference to a variable inside a function.
- */
- int c;
-
- while ( (c = getchr())!=-1 && (c==' ' || c=='\t' || c=='\n') );
- ungetchr( c );
-
- if ( c == '(' )
- {
- /*
- * Aha! it's a function call.
- */
- strcat( name, "()" );
- }
- addref( name );
- }
-
- addref( name )
- char name[];
- {
- char *cp, *getmem();
- int i;
-
- for ( i=0; i<Nextref; ++i )
- if ( !strcmp( name, Refers[ i ] ) )
- return;
-
- if ( Nextref>=MAXREFS )
- panic( "function references too many symbols" );
- cp = Refers[ Nextref++ ] = getmem( strlen( name ) + 1 );
- strcpy( cp, name );
- }
-
- compar( a, b )
- char **a, **b;
- {
- /*
- * <Compare function> for qsort().
- */
- return strcmp( *a, *b );
- }
-
- dumprefs()
- {
- /*
- * Sort and print current function's symbol reference table.
- * Reinitialize symbol reference table.
- */
- int i;
- char buf[ 80 ];
-
- if ( Nextref )
- {
- sprintf( buf, "Variables used by %s:\n", Curfunc );
- outstr( buf );
- qsort( Refers, Nextref, sizeof( Refers[0] ), compar );
- for ( i=0; i<Nextref; ++i )
- {
- sprintf( buf, "\t%s\n", Refers[ i ] );
- outstr( buf );
- free( Refers[ i ] );
- }
- outstr( "----------\n\n\n" );
- Nextref = 0;
- }
- }
-
- getoken()
- {
- /*
- * Read C tokens from current input file into the
- * token buffer. Strip out comments and whitespace in the
- * process.
- */
- char *tknptr; /* Tokenbuf pointer */
- int c; /* current input character */
-
- tknptr = Tokenbuf;
-
- top:
- if ( (c = getchr()) == -1 )
- return *Tokenbuf = Token = 0;
-
- *tknptr++ = c;
- /*
- * Skip over spaces and tabs
- */
- if ( c==' ' || c=='\t' )
- goto top;
-
- /*
- * By default, token is the first non-space character in the
- * input stream. NOTE: newlines are not considered whitespace.
- */
- Token = c;
- Tokenstart = tknptr - 1;
-
- if ( c=='\n' )
- Token = NEWLINE;
- else if ( c=='/' )
- {
- if ( (c = getchr()) == '*' )
- {
- if ( Docomments )
- *tknptr++ = '*';
- else
- --tknptr;
- while ( (c = needchr()) != -1 )
- {
- if ( Docomments )
- {
- if ( tknptr>=Tokenbuf+TOKENBUFSZ )
- panic( "buffer overflow" );
- *tknptr++ = c;
- }
- if ( c=='*' )
- {
- if ( (c = needchr()) == '/' )
- {
- if ( Docomments )
- *tknptr++ = '/';
- break;
- }
- else
- ungetchr( c );
- }
- }
- Token = ' ';
- }
- else
- ungetchr( c );
- }
- else if ( c=='#' )
- {
- while ( (c = getchr())!=-1 && (c==' ' || c=='\t') );
- do
- {
- if ( (*tknptr++ = c) == '\\' )
- *tknptr++ = getchr();
- }
- while ( (c = getchr())!=-1 && c!='\n' && c!=' ' && c!='\t' );
- ungetchr( c );
- *tknptr = 0;
-
- if ( strcmp( "#define", Tokenstart ) == 0 )
- Token = DEFINE;
- else if ( strcmp( "#include", Tokenstart ) == 0 )
- Token = INCLUDE;
- }
- else if ( c=='{' )
- ++Braces;
- else if ( c=='}' )
- --Braces;
- else if ( c=='(' )
- ++Parens;
- else if ( c==')' )
- --Parens;
- else if ( alpha( c ) )
- {
- /*
- * It's a symbol
- */
- while ( (c=getchr()) != -1 && alphanum( c ) )
- *tknptr++ = c;
- ungetchr( c );
- *tknptr = 0;
- /*
- * Check if a keyword or variable.
- */
- if ( iskeyword( Tokenstart ) )
- Token = KEYWORDS;
- else if ( Token = isdecl( Tokenstart ) )
- ;
- else
- Token = SYMBOL;
- }
- else if ( c == '"' )
- {
- /*
- * It's a string constant
- */
- tknptr = string( tknptr, '"' );
- }
- else if ( c == '\'' )
- {
- /*
- * It's a character constant
- */
- tknptr = string( tknptr, '\'' );
- }
- else if ( num( c ) )
- {
- /*
- * It's a numeric constant
- */
- while ( (c=getchr()) != -1 && hex(c) )
- *tknptr++ = c;
- ungetchr( c );
- }
- *tknptr = 0;
-
- if ( Debug>1 )
- {
- if ( Token>' ' )
- printf( "Token=%c\n", Token );
- else
- printf( "Token=<%d>\n", Token );
- if ( Debug>2 )
- printf( "<%s>\n", Tokenbuf );
- }
-
- return Token;
- }
-
- string( str, delim )
- char *str, delim;
- {
- /*
- * Compile a string from current input file into the given string
- * buffer. Stop when input character is the delimiter in "delim".
- * Returns a pointer to the first character after the string.
- */
- int c;
- char buf[ 4 ];
-
- while ( (c = getchr()) != -1 )
- {
- if ( (*str++ = c) == '\\' )
- *str++ = getchr();
- if ( c==delim )
- break;
- }
- *str = 0;
-
- return str;
- }
-
- isdecl( name )
- char name[];
- {
- if ( strcmp( "unsigned", name ) == 0 )
- return UNSIGNED;
- if ( strcmp( "char", name ) == 0 )
- return CHAR;
- if ( strcmp( "int", name ) == 0 )
- return INT;
- if ( strcmp( "long", name ) == 0 )
- return LONG;
- if ( strcmp( "float", name ) == 0 )
- return FLOAT;
- if ( strcmp( "double", name ) == 0 )
- return DOUBLE;
- if ( strcmp( "struct", name ) == 0 )
- return STRUCT;
- if ( strcmp( "union", name ) == 0 )
- return UNION;
-
- if ( strcmp( "static", name ) == 0 )
- return STATIC;
- if ( strcmp( "extern", name ) == 0 )
- return EXTERN;
- if ( strcmp( "typedef", name ) == 0 )
- return TYPEDEF;
- if ( strcmp( "register", name ) == 0 )
- return REGISTER;
- if ( strcmp( "auto", name ) == 0 )
- return AUTO;
- if ( strcmp( "void", name ) == 0 )
- return VOID;
- if ( strcmp( "enum", name ) == 0 )
- return ENUM;
- return 0;
- }
-
- iskeyword( name )
- char name[];
- {
- if ( strcmp( "if", name ) == 0 )
- return IF;
- if ( strcmp( "else", name ) == 0 )
- return ELSE;
- if ( strcmp( "for", name ) == 0 )
- return FOR;
- if ( strcmp( "do", name ) == 0 )
- return DO;
- if ( strcmp( "while", name ) == 0 )
- return WHILE;
- if ( strcmp( "break", name ) == 0 )
- return BREAK;
- if ( strcmp( "continue", name ) == 0 )
- return CONTINUE;
- if ( strcmp( "goto", name ) == 0 )
- return GOTO;
- if ( strcmp( "return", name ) == 0 )
- return RETURN;
- if ( strcmp( "switch", name ) == 0 )
- return SWITCH;
- if ( strcmp( "case", name ) == 0 )
- return CASE;
- if ( strcmp( "default", name ) == 0 )
- return DEFAULT;
- if ( strcmp( "sizeof", name ) == 0 )
- return SIZEOF;
- return 0;
- }
-
- /*
- * File I/O functions
- */
- newfile( fn )
- char *fn;
- {
- /*
- * Open the given file as the new current input file.
- */
- char msg[ 80 ];
-
- #ifdef BDS_C
- if ( fopen( fn, Fileptr ) == ERROR )
- #else
- if ( !(Fileptr = fopen( fn, "r" )) )
- #endif
- {
- sprintf( msg, "can't open file '%s'", fn );
- error( msg );
- return 0;
- }
- else
- {
- Filename = fn;
- Inline = 1;
- return 1;
- }
- }
-
- endfile()
- {
- /*
- * Close out the current input file.
- */
- fclose( Fileptr );
- Filename =
- Inline = 0;
- }
-
- pushfile()
- {
- /*
- * Push the current file information onto a stack in preparation
- * for #include file processing.
- */
- struct fstack *fsp;
-
- if ( Debug>1 )
- printf( "*** pushfile(%s)\n", Filename );
- if ( Nextfile >= FILESTACKSZ )
- panic( "#includes nested too deeply" );
- fsp = &Filestack[ Nextfile++ ];
- strcpy( fsp->fname, Filename );
- #ifdef BDS_C
- movemem( Fileptr, fsp->fptr, BUFSIZ );
- #else
- fsp->fptr = Fileptr;
- #endif
- fsp->fline = Inline;
- fsp->fbraces = Braces;
- fsp->fparens = Parens;
- Parens = Braces = 0;
- }
-
- popfile()
- {
- struct fstack *fsp;
-
- if ( Nextfile-- )
- {
- fsp = &Filestack[ Nextfile ];
- Filename = fsp->fname;
- if ( Debug>1 )
- printf( "*** popfile(%s)\n", Filename );
- #ifdef BDS_C
- movemem( fsp->fptr, Fileptr, BUFSIZ );
- #else
- Fileptr = fsp->fptr;
- #endif
- Inline = fsp->fline;
- Braces = fsp->fbraces;
- Parens = fsp->fparens;
- }
- else
- panic( "program error: popfile()" );
- }
-
- getchr()
- {
- int c;
- char esc;
-
- c = getc( Fileptr );
- #ifdef BDS_C
- if ( c=='\r' )
- {
- if ( (c = getc( Fileptr )) != '\n' )
- ungetchr( c, Fileptr );
- else
- ++Inline;
- }
- #endif
- if ( c=='\n' )
- ++Inline;
-
- return c;
- }
-
- needchr()
- {
- int c;
-
- if ( (c = getchr()) == -1 )
- error( "unexpected EOF" );
- return c;
- }
-
- ungetchr( c )
- {
- if ( c=='\n' )
- --Inline;
-
- ungetc( c, Fileptr );
- }
-
- flush()
- {
- char *cp;
-
- cp = Outbuf;
- while ( cp < Nextout )
- {
- if ( *cp == '\n' )
- if ( ++Outline >= PAGELEN )
- newpage();
- putchar( *cp++ );
- }
- Nextout = Outbuf;
- }
-
- putchr( c )
- char c;
- {
- if ( Nextout >= Outend )
- flush();
- *Nextout++ = c;
- }
-
- putstr( s )
- char *s;
- {
- while ( *s )
- {
- if ( Nextout >= Outend )
- flush();
- *Nextout++ = *s++;
- }
- }
-
- outstr( s )
- char *s;
- {
- while ( *s )
- {
- if ( *s == '\n' )
- if ( ++Outline >= PAGELEN )
- newpage();
- putchar( *s++ );
- }
- }
-
- newpage()
- {
- Outline = 3;
- printf( "\fC Variable Declarations/References in '%s'", Filename );
- printf( " Page %d\n\n\n", ++Page );
- }
-
- error( s )
- char *s;
- {
- char buf[ 80 ];
-
- if ( Filename )
- {
- sprintf( buf, "%s: ", Filename );
- outstr( buf );
- }
- if ( Inline )
- {
- sprintf( buf, "line %d: ", Inline );
- outstr( buf );
- }
- sprintf( buf, "%s\n", s );
- outstr( buf );
- }
-
- usage()
- {
- error( "Usage: var [-i] [-c] [-d] <file> ..." );
- exit( 1 );
- }
-
- panic( s )
- {
- error( s );
- exit( 2 );
- }
-
- alpha( c )
- {
- return ('A'<= c && c<='Z') || ('a'<=c && c<='z') || c=='_';
- }
-
- num( c )
- {
- return '0'<=c && c<='9';
- }
-
- alphanum( c )
- {
- return alpha( c ) || num( c );
- }
-
- hex( c )
- {
- return instring( c, "0123456789abcdefxlABCDEFXL" );
- }
-
- movemem( from, to, count )
- char *from, *to;
- unsigned count;
- {
- while ( count-- )
- *to++ = *from++;
- }
-
- char *
- getmem( size )
- unsigned size;
- {
- char *cp;
-
- if ( cp = malloc( size ) )
- return cp;
-
- panic( "out of memory" );
- }
-
- instring( c, s )
- char c, *s;
- {
- while ( *s )
- if ( c==*s++ )
- return 1;
- return 0;
- }